package ws

//go:generate gotext -srclang=zh update -out=catalog.go -lang=zh,en

import (
	"database/sql"

	w "gitee.com/tinkler/yunfei/ws"
	"gitee.com/tinkler/yunfei/ws/arsenal"
	"github.com/lib/pq"

	"github.com/dgrijalva/jwt-go"
	"github.com/kataras/iris"
	"github.com/kataras/iris/context"
)

// WS windsword
type WS struct {
	*w.WS
	*IWS
}

// IWS iris windsword
type IWS struct {
	ctx    context.Context
	isAuth bool
	claims *Claims
}

// Claims jwt ws claims
type Claims struct {
	jwt.StandardClaims
	ID       int         `json:"ID"`
	Username string      `json:"username"`
	Rolename string      `json:"rolename"`
	User     interface{} `json:"user"`
}

// S sleeve
type S struct {
	arsenal.Sleeve
	*IS
}

type IS struct {
	Status  int
	Message string
	Data    interface{}
}

// New new middleware
func New(path string) *WS {
	ws := w.TakeSwordFromYaml("wind", path)
	iris.RegisterOnInterrupt(func() {
		ws.Sheath.CloseDB()
	})
	iws := &IWS{isAuth: false}
	return &WS{ws, iws}
}

// Serve iris middleware
func (ws *WS) Serve(ctx context.Context) {
	//lang
	lang := ctx.URLParam("lang")
	// ws.Logf("当前语言：%s", lang)
	if lang == "" {
		lang = "zh"
	}
	ws.Sheath.SetLang(lang)
	if ctx.Method() == iris.MethodOptions {
		ctx.Next()
		return
	}
	ws.ctx = ctx
	ctx.Values().Set("w", ws)
	ah := ctx.GetHeader("Authorization")
	if ah == "" {
		ws.isAuth = false
		ctx.Next()
		return
	}
	token, err := jwt.ParseWithClaims(ah, &Claims{}, func(token *jwt.Token) (interface{}, error) {
		return ws.GetAuthKey(), nil
	})
	if err != nil {
		ws.Logf("auth serve error:parse token error")
		ws.Response = ws.GetS().SetError("Authorization token string is invlid")
		ctx.StopExecution()
		return
	}

	claims, ok := token.Claims.(*Claims)
	if !ok {
		ws.Logf("claims %v transfer error", token.Claims)
		ctx.StopExecution()
		return
	}
	ws.claims = claims

	ctx.Next()
}

// CreateToken create ws token
func (ws *WS) CreateToken(claims *Claims) (string, error) {
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	ss, err := token.SignedString(ws.GetAuthKey())
	if err != nil {
		return "", err
	}
	return ss, nil
}

// Defend defend the request
func (ws *WS) Defend(handle func(s *S) error, options ...string) {
	rolename := "NONE"
	username := "NONE"
	if ws.claims != nil {
		rolename = ws.claims.Rolename
		username = ws.claims.Username
	}
	_, err := ws.Sheath.GetDB().Exec("SET ROLE " + rolename)
	if err != nil {
		if pgErr, ok := err.(*pq.Error); ok {
			panic("exec set role get error:" + pgErr.Code.Name())
		}
	} else {
		// ws.Logf("当前角色：%s", rolename)
	}
	is := IS{}

	s := &S{ws.Sheath.Use(username), &is}
	p := s.GetPrinter()

	err = handle(s)
	s.Status = -1
	ws.Response.Status = 0
	ws.Response.Message = ""
	ws.Response.Data = nil
	if err != nil {
		if pgErr, ok := err.(*pq.Error); ok {
			ws.Logf("defending get error:%s", err.Error())
			switch pgErr.Code {
			case "42501":
				{
					ws.Response.Status = 1
					ws.Response.Message = p.Sprintf("权限不足")

				}
			default:
				{
					ws.Response.Status = 0
					ws.Response.Message = p.Sprintf("数据库操作错误")
				}
			}
		} else if err != sql.ErrNoRows {
			ws.Logf("defending get other error:%s", err.Error())
			ws.Response.Status = 0
			ws.Response.Message = p.Sprintf("其它未知错误")
		} else {
			ws.Response.Status = 1
			ws.Response.Message = p.Sprintf("没有数据")
		}
	} else {
		ws.Response.Status = 1
		ws.Response.Message = ""
		ws.Response.Data = s.Data
	}
	if ws.ctx != nil && ws.ctx.GetStatusCode() == 200 {

		if s.Status >= 0 {
			ws.Response.Status = s.Status
		} else if s.Data == nil {
			ws.Response.Status = 0
		}
		if s.Message != "" {
			ws.Response.Message = s.Message
		}

		ws.ctx.JSON(ws)

	}
}
